package org.aner.tester.generator.code;

import org.aner.tester.constant.Constant;
import org.aner.tester.object.ControllerObject;
import org.aner.tester.object.MethodObject;
import org.aner.tester.utils.DateUtils;
import org.aner.tester.utils.text.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * velocity template factory
 *
 * @author aner
 * @version 1.0
 * @date 2020/12/11 11:46
 */
public class VelocityFactory
{
    /**
     * the project path that test controllers are stored
     */
    private static final String PROJECT_TEST_PATH = "src/test/java/";

    /**
     * the project path that the baseControllerTest is stored
     */
    private static final String PROJECT_PATH = "src/main/java/";

    /**
     * vm initiation
     */
    public static void init()
    {
        Properties p = new Properties();
        try
        {
            // load vm file in required classpath
            p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            // set charset
            p.setProperty(Velocity.ENCODING_DEFAULT, Constant.UTF_8);
            p.setProperty(Velocity.OUTPUT_ENCODING, Constant.UTF_8);
            // init velocity engine and set properties
            Velocity.init(p);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * set variable names of template
     *
     * @param controllerObject
     * @return
     */
    public static VelocityContext prepareContext(ControllerObject controllerObject)
    {
        String packageName = controllerObject.getPackageName();
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("className", controllerObject.getClassName());
        velocityContext.put("basePackage", getPackagePrefix(packageName));
        velocityContext.put("packageName", packageName);
        velocityContext.put("datetime", DateUtils.getDate());
        velocityContext.put("importList", getImportList(controllerObject.getMethods()));
        velocityContext.put("methods", controllerObject.getMethods());
        velocityContext.put("author", "aner");

        return velocityContext;
    }

    /**
     * get template file info
     *
     * @return
     */
    public static String getTemplate()
    {
        return "vm/controller.vm";
    }

    public static List<String> getBaseControllerTestTemplate() {
        List<String> templateList = new ArrayList<>();
        templateList.add("vm/BaseControllerTest.vm");
        templateList.add("vm/AnerTesterConfig.vm");
        return templateList;
    }

    /**
     * get the file name of controllerTest
     *
     * @param packageName
     * @param className
     * @return
     */
    public static String getFileName(String packageName, String className)
    {
        String fileName = "";
        String javaPath = PROJECT_TEST_PATH + StringUtils.replace(packageName, ".", "/");
        fileName = StringUtils.format("{}/{}Test.java", javaPath, className);
        return fileName;
    }

    /**
     * get the file name of BaseControllerTest
     *
     * @return
     */
    public static String getBaseFileName(String template)
    {
        if (template.contains("BaseControllerTest")) {
            return PROJECT_TEST_PATH + "org/aner/tester/controller/BaseControllerTest.java";
        } else {
            return PROJECT_TEST_PATH + "org/aner/tester/controller/TesterConfig.java";
        }

    }

    /**
     * get package prefix
     *
     * @param packageName
     * @return
     */
    public static String getPackagePrefix(String packageName)
    {
        int lastIndex = packageName.lastIndexOf(".");
        String basePackage = StringUtils.substring(packageName, 0, lastIndex);
        return basePackage;
    }

    /**
     * get import list
     *
     * @param methods
     * @return
     */
    public static HashSet<String> getImportList(List<MethodObject> methods)
    {
        HashSet<String> importList = new HashSet<String>();
        for (MethodObject method : methods)
        {
            importList.addAll(method.getValueObjects().stream().map(p -> p.getTypeName()).collect(Collectors.toList()));
        }
        return importList;
    }

}
